# -*- coding: utf-8 -*-
# time: 2025/8/9 16:16
# file: views.py
# author: kai
# email: 1071664616@qq.com

"""
用户视图
"""
import random
import string

from django.core.cache import cache
from django.conf import settings
from decouple import config
from rest_framework.throttling import AnonRateThrottle
import picologging as logging
from rest_framework import generics, status, permissions, views
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework_simplejwt.tokens import RefreshToken
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse

from .models import User
from .serializers import (
    UserSerializer,
    UserListSerializer,
    UserProfileSerializer,
    PhoneAuthSerializer,
    AdminTokenObtainPairSerializer,
    AdminCreateSerializer
)
from services.sms_service import send_sms

logger = logging.getLogger("users.views")

@extend_schema_view(
    post=extend_schema(
        summary="管理员登录",
        description="管理员通过手机号和密码进行登录。",
        tags=['用户认证'],
        request=AdminTokenObtainPairSerializer,
        responses={
            200: OpenApiResponse(
                response={
                    'type': 'object',
                    'properties': {
                        'refresh_token': {'type': 'string'},
                        'access_token': {'type': 'string'},
                        'username': {'type': 'string'},
                        'user_type': {'type': 'string'},
                        'phone_number': {'type': 'string'}
                    }
                },
                description='登录成功'
            ),
            400: OpenApiResponse(description='手机号或密码错误')
        }
    )
)
class AdminLoginView(views.APIView):
    """
    管理员用户名+密码登录视图
    """
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = AdminTokenObtainPairSerializer(data=request.data)
        if serializer.is_valid():
            return Response(serializer.validated_data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@extend_schema_view(
    post=extend_schema(
        summary="手机号登录/注册",
        description="通过手机号和验证码进行登录，如果用户不存在则自动注册新用户。",
        tags=['用户认证'],
        request=PhoneAuthSerializer,
        responses={
            200: OpenApiResponse(
                response={
                    'type': 'object',
                    'properties': {
                        'message': {'type': 'string', 'example': '登录成功'},
                        'access': {'type': 'string'},
                        'refresh_token': {'type': 'string'},
                        'user': {'type': 'object'}
                    }
                },
                description='登录成功'
            ),
            400: OpenApiResponse(description='验证码错误或请求参数错误')
        }
    )
)
class PhoneLoginView(views.APIView):
    """
    手机号登录视图（自动注册）
    """
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = PhoneAuthSerializer(data=request.data)
        if serializer.is_valid():
            phone_number = serializer.validated_data['phone_number']
            input_verification_code = request.data.get('input_verification_code')
            # 检查是否使用固定验证码模式
            use_fixed_code = config('USE_FIXED_VERIFICATION_CODE', default=False, cast=bool)
            fixed_code = config('SMS_VERIFICATION_CODE', default='123456')
            
            # 如果是固定验证码模式且输入的是固定验证码，直接通过验证
            if use_fixed_code and input_verification_code == fixed_code:
                logger.info(f"测试模式：使用固定验证码 {fixed_code} 登录")
            else:
                # 从缓存中获取生成的验证码进行比较
                cached_code = cache.get(f'verification_code_{phone_number}')
                if not cached_code or cached_code != input_verification_code:
                    logger.error("验证码错误或已过期")
                    return Response({'message': '验证码错误或已过期'}, status=status.HTTP_400_BAD_REQUEST)
            # 验证普通用户（不能是管理员）
            user, created = User.objects.get_or_create(
                phone_number=phone_number,
                defaults={
                    'username': f'user_{"".join(random.choices(string.ascii_letters + string.digits, k=8))}',
                    'user_type': 'user'
                }
            )
            # 确保不是管理员账户
            if user.user_type == 'admin':
                logger.error("管理员账户不能通过短信验证码登录")
                return Response({'message': '管理员账户不能通过短信验证码登录'}, status=status.HTTP_400_BAD_REQUEST)
            # 生成JWT
            refresh = RefreshToken.for_user(user)
            response_data = {
                'message': '登录成功' if not created else '注册并登录成功',
                'access': str(refresh.access_token),
                'refresh_token': str(refresh),
                'user': UserSerializer(user).data
            }
            logger.info("用户登录成功")
            # 清除已使用的验证码
            cache.delete(f'verification_code_{phone_number}')
            return Response(response_data, status=status.HTTP_200_OK)
        else:
            logger.error("登录请求参数错误")
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@extend_schema_view(
    post=extend_schema(
        summary="生成验证码",
        description="为指定手机号生成6位数字验证码并缓存10分钟。",
        tags=['用户认证'],
        request={'phone_number': str},
        responses={
            200: OpenApiResponse(
                response={
                    'type': 'object',
                    'properties': {
                        'message': {'type': 'string', 'example': '验证码已发送'}
                    }
                },
                description='验证码发送成功'
            ),
            400: OpenApiResponse(description='手机号格式错误或为空'),
            429: OpenApiResponse(description='请求过于频繁')
        }
    )
)
class GenerateVerificationCodeView(views.APIView):
    """
    生成验证码视图
    """
    permission_classes = [permissions.AllowAny]
    throttle_classes = [AnonRateThrottle]  # 添加频率限制，防止恶意请求

    def post(self, request):
        phone_number = request.data.get('phone_number')
        if not phone_number:
            logger.error("手机号不能为空")
            return Response({'message': '手机号不能为空'}, status=status.HTTP_400_BAD_REQUEST)
        # 验证手机号格式（可选）
        if not phone_number.isdigit() or len(phone_number) != 11:
            logger.error("手机号格式错误")
            return Response({'message': '手机号格式不正确'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 根据配置决定验证码生成方式
        if hasattr(settings, 'USE_FIXED_VERIFICATION_CODE') and settings.USE_FIXED_VERIFICATION_CODE:
            # 测试模式：使用固定验证码（用于Locust性能测试）
            verification_code = settings.SMS_VERIFICATION_CODE if hasattr(settings, 'SMS_VERIFICATION_CODE') else '123456'
            logger.info(f"测试模式：已生成固定验证码：{verification_code}")
        else:
            # 生产模式：生成随机验证码
            verification_code = ''.join(random.choices(string.digits, k=6))
            logger.info(f"生产模式：已生成随机验证码：{verification_code}")
        
        # 保存验证码到缓存, 有效期 5分钟
        cache.set(f'verification_code_{phone_number}', verification_code, timeout=300)
        
        # 调用短信服务发送验证码
        send_ret = send_sms(verification_code, phone_number)
        if send_ret:
            # 根据配置返回不同的消息
            if hasattr(settings, 'USE_FIXED_VERIFICATION_CODE') and settings.USE_FIXED_VERIFICATION_CODE:
                logger.info("测试模式：验证码已生成（未发送真实短信）")
                return Response({
                    'message': '验证码已生成',
                    'test_mode': True,
                    'verification_code': verification_code  # 测试模式下返回验证码
                }, status=status.HTTP_200_OK)
            else:
                logger.info(f"验证码已发送到 {phone_number}")
                return Response({
                    'message': '验证码已发送'
                }, status=status.HTTP_200_OK)
        else:
            logger.error("短信服务发送失败")
            return Response({'message': '短信服务发送失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class IsAdminUser(permissions.BasePermission):
    """
    自定义权限类，只允许管理员访问
    """
    def has_permission(self, request, view):
        return request.user.is_authenticated and request.user.user_type == 'admin'

@extend_schema_view(
    get=extend_schema(
        summary="获取用户列表",
        description="管理员获取所有用户列表",
        tags=['用户管理'],
        responses={
            200: UserListSerializer(many=True),
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足')
        }
    )
)
class UserListView(generics.ListAPIView):
    """
    获取用户列表（仅管理员）
    """
    serializer_class = UserListSerializer
    permission_classes = [IsAdminUser]
    pagination_class = PageNumberPagination

    def get_queryset(self):
        queryset = User.objects.all()
        # 支持按用户类型筛选
        user_type = self.request.query_params.get('user_type', None)
        if user_type:
            queryset = queryset.filter(user_type=user_type)
        # 支持按用户名筛选
        username = self.request.query_params.get('username', None)
        if username:
            queryset = queryset.filter(username__icontains=username)
        return queryset

@extend_schema_view(
    get=extend_schema(
        summary="获取当前用户信息",
        description="获取当前登录用户的完整个人信息。",
        tags=['用户管理'],
        responses={
            200: UserProfileSerializer,
            401: OpenApiResponse(description='未认证')
        }
    ),
    put=extend_schema(
        summary="更新当前用户信息",
        description="完全更新当前登录用户的个人信息。",
        tags=['用户管理'],
        request=UserProfileSerializer,
        responses={
            200: UserProfileSerializer,
            400: OpenApiResponse(description='请求参数错误'),
            401: OpenApiResponse(description='未认证')
        }
    ),
    patch=extend_schema(
        summary="部分更新当前用户信息",
        description="部分更新当前登录用户的个人信息。",
        tags=['用户管理'],
        request=UserProfileSerializer,
        responses={
            200: UserProfileSerializer,
            400: OpenApiResponse(description='请求参数错误'),
            401: OpenApiResponse(description='未认证')
        }
    )
)
@permission_classes([permissions.IsAuthenticated])
class UserProfileView(generics.RetrieveUpdateAPIView):
    """
    用户个人信息视图
    """
    serializer_class = UserProfileSerializer

    def get_object(self):
        return self.request.user


@extend_schema_view(
    post=extend_schema(
        summary="创建管理员账户",
        description="管理员创建新的管理员账户",
        tags=['用户管理'],
        request=AdminCreateSerializer,
        responses={
            201: UserSerializer,
            400: OpenApiResponse(description='请求参数错误'),
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足')
        }
    )
)
class AdminCreateView(generics.CreateAPIView):
    """
    创建管理员账户（仅管理员）
    """
    queryset = User.objects.all()
    serializer_class = AdminCreateSerializer
    permission_classes = [IsAdminUser]

    def perform_create(self, serializer):
        serializer.save(user_type='admin')

@extend_schema_view(
    get=extend_schema(
        summary="获取用户详情",
        description="获取指定用户的详细信息。管理员可以查看所有用户，普通用户只能查看自己",
        tags=['用户管理'],
        responses={
            200: UserListSerializer,
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足'),
            404: OpenApiResponse(description='用户不存在')
        }
    ),
    put=extend_schema(
        summary="更新用户信息",
        description="完全更新用户信息。仅管理员可以操作",
        tags=['用户管理'],
        request=UserSerializer,
        responses={
            200: UserSerializer,
            400: OpenApiResponse(description='请求参数错误'),
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足'),
            404: OpenApiResponse(description='用户不存在')
        }
    ),
    patch=extend_schema(
        summary="部分更新用户信息",
        description="部分更新用户信息。仅管理员可以操作",
        tags=['用户管理'],
        request=UserSerializer,
        responses={
            200: UserSerializer,
            400: OpenApiResponse(description='请求参数错误'),
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足'),
            404: OpenApiResponse(description='用户不存在')
        }
    ),
    delete=extend_schema(
        summary="删除用户",
        description="删除指定用户。仅管理员可以操作",
        tags=['用户管理'],
        responses={
            204: OpenApiResponse(description='删除成功'),
            401: OpenApiResponse(description='未认证'),
            403: OpenApiResponse(description='权限不足'),
            404: OpenApiResponse(description='用户不存在')
        }
    )
)
class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
    """
    用户详情、更新、删除（管理员可以操作所有用户，普通用户只能操作自己）
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

    def get_permissions(self):
        if self.request.method == 'GET':
            # 查看用户信息需要认证
            return [permissions.IsAuthenticated()]
        else:
            # 修改和删除需要管理员权限
            return [IsAdminUser()]

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return UserListSerializer
        return UserSerializer

    def get_object(self):
        # 如果是非管理员用户访问，只能获取自己的信息
        user = self.request.user
        if user.user_type != 'admin':
            return user
        return super().get_object()

    def perform_destroy(self, instance):
        # 软删除：将用户状态设置为非活跃
        instance.is_active = False
        instance.save()

    def update(self, request, *args, **kwargs):
        # 重写更新方法，支持激活/禁用用户
        if 'is_active' in request.data and len(request.data) == 1:
            # 只更新状态
            instance = self.get_object()
            instance.is_active = request.data['is_active']
            instance.save()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
        # 其他更新操作使用默认逻辑
        return super().update(request, *args, **kwargs)

@extend_schema(
    summary="用户登出",
    description="用户退出登录，删除认证令牌",
    tags=['用户认证'],
    responses={
        200: OpenApiResponse(
            response={
                'type': 'object',
                'properties': {
                    'message': {'type': 'string', 'example': '登出成功'}
                }
            },
            description='登出成功'
        ),
        400: OpenApiResponse(description='登出失败'),
        401: OpenApiResponse(description='未认证')
    }
)
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def user_logout(request):
    """
    用户登出接口 - JWT版本
    """
    try:
        # 检查 refresh_token 是否存在于请求数据中
        if "refresh_token" not in request.data or not request.data["refresh_token"]:
            logger.error("用户未提供有效的refresh_token")
            return Response({
                'error': '请提供有效的refresh_token'
            }, status=status.HTTP_400_BAD_REQUEST)
        refresh_token = request.data.get("refresh_token")
        if refresh_token:
            token = RefreshToken(refresh_token)
            token.blacklist()
            logger.info("用户已登出")
            return Response({
                'message': '登出成功'
            }, status=status.HTTP_200_OK)
        logger.error("用户未提供refresh_token")
        return Response({
            'error': '请提供refresh_token'
        }, status=status.HTTP_400_BAD_REQUEST)
    except:
        logger.error("用户登出失败")
        return Response({
            'error': '登出失败'
        }, status=status.HTTP_400_BAD_REQUEST)
